Spring的web MVC框架和其他web MVC框架一样,由注解驱动,围绕着一个核心的用来分发请求到控制器的Servlet设计,并提供了其他的功能来简便web应用程序开发。但是,DispathcerServlet
做的远不止这些。它完全集成了Spring IoC容器,让你允许使用其他Spring的功能。
Spring Web MVC的DispatcherServlet
工作流程如下图所示。了解设计模式的读者会意识到DispatcherServlet
是Front Controller
设置模式的一种(这种模式被Spring Web MVC和其他领先的web框架所共享)。
Figure 22.1. The request processing workflow in Spring Web MVC(high level)
DispatcherServlet
实际上就是一个Servlet
(继承了HttpServlet
),因此可以被声明在你的web应用中。你需要通过URL mapping映射到你希望DispatcherServlet
处理的请求。下面是一个Servlet 3.0+的环境中标准的Java EE Servlet配置:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());
registration.setLoadOnStartup(1);
registration.addMapping("/example/*");
}
}
上面这个例子中,任何以/example
开头的请求会被叫做example
的DispathcerServlet
处理。
WebApplicationInitializer
是Spring MVC提供的接口,让你基于代码的配置可以被检测并自动应用到任何Servlet 3容器中。这个接口抽象的实现是AbstractAnnotationConfigDispathcerServletInitializer
,它使注册DispathcerServlet
更容易,只要简单的指定它的servlet映射和配置类列表——也建议你用这种方式类设置你的Spring MVC应用。查看Code-based Servlet container initializaiont了解更多信息。
DispathcerServlet
是一个Servlet
(继承自HttpServlet
),因此可以在你的web application的web.xml
中声明。你需要在相同的web.xml
中用URL mapping指定你希望DispathcerServlet
处理的请求。它是一个标准的Java EE Servlet配置;下面的例子展示了如何声明和映射DispatcherServlet
:
下面的web.xml
和上面的基于代码的配置是相同的:
<web-app>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>/example/*</url-pattern>
</servlet-mapping>
</web-app>
Spring中ApplicationContext
实例可以被设置范围,具体见7.15节,"Additional capabilities of the ApplicationContext"。在Web MVC框架中,每个DispatcherServlet
有它自己的WebApplicationContext
,每个WebApplicationContext
继承了定义在根WebApplicationContext
。根WebApplicationContext
应该包含所有需要被其他context或是Servlet实例共享的bean结构。这些继承来的bean可以在servlet-特指的范围下被覆盖,并且你可以为servlet实例定义bean的新的特定的范围。
Figure 22.2. Typical context hierarchy in Spring Web MVC
在DispatcherServlet
初始化之后,Spring MVC会在你web应用的WEB-INF
下查找一个叫[servlet-name]-servlet.xml的文件,并创建定义在这个文件中的bean,覆盖全局范围下的相同名字的bean定义。
考虑(在web.xml
中)有下面DispatcherServlet
Servlet配置:
<web-app>
<servlet>
<servlet-name>golfing</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>golfing</servlet-name>
<url-pattern>/golfing/*</url-pattern>
</servlet-mapping>
</web-app>
在你的应用中需要一个叫做/WEB-INF/golfing-servlet.xml
的文件;这个文件将包含你所有的特定于Spring Web MVC的组件(beans)。你可以通过Servlet初始化的参数来改变这个配置文件的实际位置(详见下面)。
当然在只有一个DispatcherServlet的环境下,只有根上下文也是可以的。
可以通过像下面这个,设置空的contextConfigLocation作为servlet初始化参数来实现:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
WebApplicationContext
拓展了ApplicationContext
,增加了web应用必要的一些功能。和普通ApplicationContext
不同,它可以解析主题(见22.9节,"Using themes"),并且它(通过连接到ServletContext
)知道和哪个Servlet关联。WebApplication
和ServletContext
绑定,在你需要访问WebApplicationContext
时,通过RequestContextUtis
的静态方法可以查找到WebApplication
。
我们也可以用基于Java的方式实现上面的配置:
public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// GolfingAppConfig defines beans that would be in root-context.xml
return new Class[] { GolfingAppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
// GolfingWebConfig defines beans that would be in golfing-servlet.xml
return new Class[] { GolfingWebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/golfing/*" };
}
}
Spring DispatcherServlet
用特殊的bean来处理请求和渲染合适的视图。这些bean是Spring MVC的一部分。你可以选择WebApplicationContext
简单的配置一个或多个这些特殊的bean。如果你没有做任何配置,Spring MVC会用一系列的默认的Bean,因此你不是非配置这些bean不可。首先,看一下DispatcherServlet
依赖的这些特殊的bean的表。
Table 22.1. Specail bean types in the WebApplicationContext
Bean类型 | 说明 |
---|---|
HandlerMapping | 将进来的请求映射到处理器上,并且有一系列前置和后置的处理器(处理器拦截器),处理器的具体细节由HandlerMapping 实现决定。最常见的实现支持被注解的控制器,但也存在其他实现。 |
HandlerAdapter | 帮助DispatcherServlet 调用请求映射的处理器,但不管吃力气是否真的被调用。比如,调用被注解的控制器需要解析多个注解。因此,HandlerAdapter 的主要目的是让DispatcherServlet 不在关注这些细节。 |
HandlerExceptionResolver | 将异常映射到视图,同时也允许更复杂的异常处理代码 |
ViewResolver | 解析基于字符串的试图名字到真正的View 类型 |
LocaleResolver & LocaleContextResolver | 解析客户端正在使用的语言环境和时区,以便提供国际化的试图 |
ThemeResovler | 解析你应用环境可以使用的主题,比如,提供个性化的布局 |
MultipartResolver | 解析multi-part请求,比如,支持处理从HTML表单上传的文件 |
FlashMapManager | 存储和检索“输入”和“输出”FlashMap ,用来从一个请求传递属性到另一个请求,通常通过重定向 |
当你设置完DispatcherServlet
,一个请求进到这个DispatcherServlet
中,DispatcherServlet
开始以下列顺序处理请求:
WebApplicationContext
被绑定为请求的属性,供控制器和其他元素搜索和使用。(绑定的默认的key为DispatcherServlet.WEb_APPLICATON_CONTEXT_ATTRIBUTE
)。
语言环境解析器被绑定为请求的属性,使得在处理请求时(渲染视图,准备数据,等等),能够解析语言环境并使用。
* 如果你指定了一个multipart文件解析器,将检查请求是否有multiparts;如果发现了multiparts,请求将会被包装秤MultipartHttpServletReqeust
,在过程中由其他元素更胜、深层的处理。见[22.10节,"Springs multipart (file upload) support"](https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#mvc-multipart)了解更多关于multipart处理。
* 搜索合适的处理器。如果发现了这个处理器,执行和这个处理器相关联的执行链(包含了前置处理器,后置处理器和控制器)会为准备模型或渲染被执行。
* 如果返回了一个模型,那么视图会被渲染。如果没有返回模型,(可能是前置处理器或后置处理器处于安全原因拦截了请求,)将不会有视图被渲染,因为请求已经完成了。
Spring
DispatcherServlet也支持返回最后修改日期,由Servlet API特指的。为特定的请求检测最后修改日期的过程非常直接:
DispatcherServlet查看合适的处理器映射,并测试这个处理器是否实现了
LastModified接口。如果是,那么
LastModified接口的
long getLastModified(reqesut)方法的值会被返回到客户端。
你可以通过在声明Servlet时,往
web.xml文件中添加Servlet初始化参数(
init-param元素)来自定义你的
DispatcherServlet`实例。下表列出了所支持的参数。
Table 22.2. DispathcerServlet initialization parameters
参数 | 说明 |
---|---|
contextClass |
实现了WebApplicationContext 的类,它为Servlet初始化了上下文环境。默认使用XmlWebApplicationContext |
contextConfigLocation |
传给(由contextClass指定的)上下文实例的字符串,用来指定context的位置。字符串由多个字符串组成(用逗号分隔)来支持多个上下文。如果多个上下文中有bean被定义了两次,那么后定义的bean优先级更高 |
namespace |
WebApplicationContext 的命名空间,默认是[servlet-name]-servlet 。 |